package com.pine.app.module.security.oauth.plugin.impl.validateParams;

import com.pine.app.module.security.core.common.AuthConstant;
import com.pine.app.module.security.core.common.enums.ErrorType;
import com.pine.app.module.security.core.common.enums.GrantType;
import com.pine.app.module.security.core.common.enums.ResponseProduceType;
import com.pine.app.module.security.core.common.enums.ResponseType;
import com.pine.app.module.security.oauth.exception.AuthenticationException;
import com.pine.app.module.security.oauth.plugin.AbstractProcessPlugin;
import com.pine.app.module.security.oauth.plugin.Plugin;
import com.pine.app.module.security.oauth.provider.client.ClientDetails;
import com.pine.app.module.security.oauth.provider.client.ClientDetailsService;
import com.pine.app.module.security.oauth.support.code.AuthorizationCodeRequest;
import com.pine.app.module.security.oauth.support.code.HttpAuthorizationCodeRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author xiaoyuan
 * @create 2020/3/8 22:14
 **/
@Slf4j
public class ValidateParamsPlugin extends AbstractProcessPlugin {

    private ClientDetailsService clientDetailsService;


    @Autowired
    public void setClientDetailsService(ClientDetailsService clientDetailsService) {
        this.clientDetailsService = clientDetailsService;
    }

    @Override
    public void init() {
        log.info("登陆页面和登陆接口的参数校验插件初始化成功");
    }

    @Override
    public void prepare(HttpServletRequest request, HttpServletResponse response, Object o) throws ServletException, IOException {
       // log.info("开始执行登陆页面和登陆接口的参数校验插件");
        //移除掉上一次的异常信息
        request.removeAttribute(AuthConstant.DEFAULT_LOGIN_ERROR_KEY);
        //获取请求数据
        AuthorizationCodeRequest authorizationCodeRequest = new HttpAuthorizationCodeRequest(request);
        //检查客户端信息是否合法   如果通过返回客户端信息
        ClientDetails clientDetails = checkClientInfo(authorizationCodeRequest.getClientId());
        //把客户端的名字放到页面中
        request.setAttribute(AuthConstant.APP_NAME_KEY, clientDetails.getClientName());
        //检查responseType的类型是否错误
        checkResponseType(authorizationCodeRequest.getResponseType());
        String error_message = "";
        //如果responseType的类型为token 简化模式  那么就直接返回token
        if (ResponseType.TOKEN.getCode().equalsIgnoreCase(authorizationCodeRequest.getResponseType())) {
//            if (!clientDetails.getAuthorizedGrantTypes().contains(GrantType.IMPLICIT.getName())) {
//                throw new AuthenticationException(ErrorType.UNSUPPORTED_GRANT_TYPE,"此客户端不支持简化模式", ResponseProduceType.HTML, AuthConstant.DEFAULT_LOGIN_PATH);
//            }
            error_message = "此客户端不支持简化模式";
        }
        //如果responseType的类型为code 授权码模式  那么就直接返回code
        if (ResponseType.CODE.getCode().equalsIgnoreCase(authorizationCodeRequest.getResponseType())) {
//            if (!clientDetails.getAuthorizedGrantTypes().contains(GrantType.AUTHORIZATION_CODE.getName())) {
//                throw new AuthenticationException(ErrorType.UNSUPPORTED_GRANT_TYPE,"此客户端不支持授权码模式", ResponseProduceType.HTML, AuthConstant.DEFAULT_LOGIN_PATH);
//            }
            error_message = "此客户端不支持授权码模式";
        }
        //检查redirectUri是否正确
        checkRedirectUri(authorizationCodeRequest.getRedirectUri());
        //检查跳转页面是否为注册的页面
        if (clientDetails.getRegisteredRedirectUri() == null || !clientDetails.getRegisteredRedirectUri().contains(authorizationCodeRequest.getRedirectUri())) {
        //    throw new AuthenticationException(ErrorType.ILLEGAL_REDIRECT_URI, "跳转链接不是注册时的跳转链接", ResponseProduceType.HTML, AuthConstant.DEFAULT_LOGIN_PATH);
            error_message = "跳转链接不是注册时的跳转链接";
        }
        if(StringUtils.isNotBlank(error_message)){
            request.setAttribute(AuthConstant.DEFAULT_LOGIN_ERROR_KEY,error_message);
            RequestDispatcher dispatcher = request.getRequestDispatcher(AuthConstant.DEFAULT_LOGIN_PATH);
            dispatcher.forward(request, response);
        }

    }

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public boolean matcher(HttpServletRequest request, Plugin plugin) {
        return matcher("clientVlidate", plugin);
    }


    private ClientDetails checkClientInfo(String clientId) {

        if (StringUtils.isBlank(clientId)) {
            throw new AuthenticationException(ErrorType.CLIENT_NOT_NULL, ResponseProduceType.HTML, AuthConstant.DEFAULT_LOGIN_PATH);
        }
        ClientDetails clientDetails = this.clientDetailsService.loadClientDetail(clientId);
        if (clientDetails == null || clientDetails.isExpiredTime()) {
            throw new AuthenticationException(ErrorType.ILLEGAL_CLIENT_ID, ResponseProduceType.HTML, AuthConstant.DEFAULT_LOGIN_PATH);
        }
        return clientDetails;
    }

    private void checkResponseType(String responseType) {
        if (StringUtils.isBlank(responseType)) {
            throw new AuthenticationException(ErrorType.RESPONSE_TYPE_NOT_NULL, ResponseProduceType.HTML, AuthConstant.DEFAULT_LOGIN_PATH);
        }
        ResponseType type = ResponseType.getByCode(responseType);
        if (type == null) {
            throw new AuthenticationException(ErrorType.UNSUPPORTED_RESPONSE_TYPE, ResponseProduceType.HTML, AuthConstant.DEFAULT_LOGIN_PATH);
        }
    }

    private void checkRedirectUri(String redirectUri) {
        if (StringUtils.isBlank(redirectUri)) {
            throw new AuthenticationException(ErrorType.REDIRECT_URI_NOT_NULL, ResponseProduceType.HTML, AuthConstant.DEFAULT_LOGIN_PATH);
        }
        if (!redirectUri.matches("^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]")) {
            throw new AuthenticationException(ErrorType.REDIRECT_URI_NOT_NULL, "redirect_uri错误，非uri连接", ResponseProduceType.HTML, AuthConstant.DEFAULT_LOGIN_PATH);
        }

    }
}
